﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoccerSimulator5000
{
    public class Match
    {
        public Team homeTeam {get; set;}
        public Team awayTeam { get; set; }

        public int attendance { get; set; }
        
        public bool homeTeamWin = false;
        public bool awayTeamWin = false;

        public int homeGoals { get; set; }
        public int awayGoals { get; set; }
        
        public int roundNumber { get; set; }

        public Date date { get; set; }

        public Match()
        {

        }

        public Match(Team home, Team away, int round )
        {
            roundNumber = round;
            homeTeam = home;
            awayTeam = away;
            homeGoals = 0;
            awayGoals = 0;
            this.date = new Date(round-1);
        }

        public void Draw(int x, int y, System.Drawing.Graphics g)
        {
            System.Drawing.Font theFont = new System.Drawing.Font("Courier New", 15);
            object[] arg = { homeTeam.name, homeGoals, awayGoals, awayTeam.name };
            string match = string.Format("{0,-20}{1,2}-{2,-2}{3,20}", arg);

            g.FillRectangle(System.Drawing.Brushes.Aquamarine, x, y, 750, 40);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Black), x, y, 750, 40);
            g.DrawString(match, theFont, System.Drawing.Brushes.Black, x+50, y+10);
        }

        public void PrintMatchToConsole()
        {
            System.Console.WriteLine("Round: " + roundNumber + " Home: " + homeTeam.name + " Away: " + awayTeam.name + "\n");
        }

        public void CalculateAttendance()
        {
            int teamStandingsDiff = Math.Abs(homeTeam.standingsData.position - awayTeam.standingsData.position);
            float penalty = 1;

            // If any, calculate penalty.

            if (teamStandingsDiff / 3 == 1)
            {
                penalty = (float)0.8;
            }
            else if (teamStandingsDiff / 3 == 2)
            {
                penalty = (float)0.6;
            }
            else if (teamStandingsDiff / 3 == 3 )
            {
                penalty = (float)0.45;
            }

            if (this.roundNumber == 1)
            {
                attendance = homeTeam.finance.stadium.seats; // All stadiums are always filled att the season premiere. 
            }
            else
            {
                if (homeTeam.standingsData.position > 0 && homeTeam.standingsData.position < 4) // If hometeam is in first group of three
                {
                    // 95% chance of filled stadium if diff between teams is 1, 90% chance if diff = 2                   
                    if ( Math.Abs(teamStandingsDiff) == 1)
                    {
                        if (Game.random.Next(0, 100) < 95) // 95% chance of filled stadium
                        {
                            attendance = homeTeam.finance.stadium.seats;
                        }
                        else
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else if ( Math.Abs(teamStandingsDiff) == 2)
                    {
                        if (Game.random.Next(0, 100) < 90) // 90% chance of filled stadium
                        {
                            attendance = homeTeam.finance.stadium.seats;
                        }
                        else
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else
                    {
                        // Larger diff in standings means that the teams are in different groups of three.
                        attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                    }
                }
                else if (homeTeam.standingsData.position > 3 && homeTeam.standingsData.position < 7)
                {
                    if (Math.Abs(teamStandingsDiff) == 1)
                    {
                        if (Game.random.Next(0, 100) < 80) // 80% chance of filled stadium
                        {
                            attendance = homeTeam.finance.stadium.seats;
                        }
                        else
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else if (Math.Abs(teamStandingsDiff) == 2)
                    {
                        if (Game.random.Next(0, 100) < 70) // 70% chance of filled stadium
                        {
                            attendance = homeTeam.finance.stadium.seats;
                        }
                        else
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else
                    {
                        // Larger diff in standings means that the teams are in different groups of three.
                        attendance = (int)(homeTeam.finance.stadium.seats * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                    }
                }
                else if (homeTeam.standingsData.position > 6 && homeTeam.standingsData.position < 10)
                {
                    if (Math.Abs(teamStandingsDiff) == 1)
                    {
                        if (Game.random.Next(0, 100) < 95) // 95% chance of 80% filled stadium
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * 0.8);
                        }
                        else
                        {
                            attendance = (int)((homeTeam.finance.stadium.seats * 0.8) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else if (Math.Abs(teamStandingsDiff) == 2)
                    {
                        if (Game.random.Next(0, 100) < 90) // 90% chance of 80% filled stadium
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * 0.8);
                        }
                        else
                        {
                            attendance = (int)((homeTeam.finance.stadium.seats * 0.8) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else
                    {
                        // Larger diff in standings means that the teams are in different groups of three.
                        attendance = (int)((homeTeam.finance.stadium.seats * 0.8) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                    }
                }
                else
                {
                    if (Math.Abs(teamStandingsDiff) == 1)
                    {
                        if (Game.random.Next(0, 100) < 80) // 80% chance of 60% filled stadium
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * 0.6);
                        }
                        else
                        {
                            attendance = (int)((homeTeam.finance.stadium.seats * 0.6) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else if (Math.Abs(teamStandingsDiff) == 2)
                    {
                        if (Game.random.Next(0, 100) < 70) // 70% chance of 60% filled stadium
                        {
                            attendance = (int)(homeTeam.finance.stadium.seats * 0.6);
                        }
                        else
                        {
                            attendance = (int)((homeTeam.finance.stadium.seats * 0.6) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                        }
                    }
                    else
                    {
                        // Larger diff in standings means that the teams are in different groups of three.
                        attendance = (int)((homeTeam.finance.stadium.seats * 0.6) * ((1 / ((float)teamStandingsDiff / 3)) * penalty));
                    }
                }
            }
        }

        public void PlayMatch()
        {
            CalculateAttendance();
            // Calculate the total possession and each teams percentage of possession.
            // Home team gets +10 to their midfieldScore to represent the "homefield-advantage"
            float posessionTotal = (awayTeam.teamData.midfieldScore + 5) + homeTeam.teamData.midfieldScore;
            float homeTeamPosession = (homeTeam.teamData.midfieldScore + 5) / posessionTotal;
            float awayTeamPosession = awayTeam.teamData.midfieldScore / posessionTotal;


            // Decide the total number of attack opportunities that occur during the duration of the match.
            // Also decide the duration of the match.
            int totalAdvanceOpportunities = Game.random.Next(35, 55);
            int matchDuration = Game.random.Next(90, 96);
           
            // Crate an array and populate it with the timestamp of each attack opportunity.
            int tempMinute;
            System.Collections.ArrayList advanceMinutes = new System.Collections.ArrayList();

            for (int i = 0; i < totalAdvanceOpportunities; i++)
            {
                // The do-while loop randomly draw a "minute" from the pool of matchduration minutes.
                // It continues to draw a new minute if the drawn number already exists in the arraylist.
                // This ensures that no two attack opportunities can occur on the same minute. Good or bad is for someone else to decide.
                do
                {
                    tempMinute = Game.random.Next(1, matchDuration + 1);
                }
                while ( advanceMinutes.Contains(tempMinute));

                advanceMinutes.Add(tempMinute);
            }

            // Sort the arraylist so that the attack opportunities can occur in chronological order.
            advanceMinutes.Sort();

            foreach (var minute in advanceMinutes)
            {  

                int randomPossession = Game.random.Next(0, 100);

                if (randomPossession < (homeTeamPosession * 100))
                {
                    //Home Team attacks
                    SimulateAdvance(homeTeam, awayTeam);
                }
                else
                {
                    // Away Team attacks
                    SimulateAdvance(awayTeam, homeTeam);
                    
                }
            }
            

            if (homeGoals > awayGoals)
            {
                homeTeamWin = true;
                awayTeamWin = false;
            }
            else if (awayGoals > homeGoals)
            {
                awayTeamWin = true;
                homeTeamWin = false;
            }
            else
            {
                awayTeamWin = true;
                homeTeamWin = true;
            }
            AppointPoints();
            homeTeam.finance.AddMatchIncome(attendance);
        }

        public void SimulateAdvance(Team attacking, Team defending)
        {
            // Determine attack% of attacking team and defend% of defending team.
            float totalPool = attacking.teamData.forwardScore + (defending.teamData.defenderScore + (defending.teamData.midfieldScore / 2 ) + (defending.teamData.forwardScore / 3));
            float attackingRange = attacking.teamData.forwardScore / totalPool;
            float defendingRange = (defending.teamData.defenderScore + (defending.teamData.midfieldScore / 2) + (defending.teamData.forwardScore / 3)) / totalPool;

           
            // Checks to see if advance is successful
            int randomRange = Game.random.Next(0, 100);
            // If number is in attackingAttack range - advance is successful.
            if (randomRange < (attackingRange * 100))
            {
                // Successful advance
                SimulateAttack(attacking, defending); 
            }
            else
            {
                // Successful defending.
                // go back to simulating next advance
            }

        }

        public void SimulateAttack(Team attacking, Team defending)
        {
            // Determine new attack% of attacking team and defend% of defending team.
            float totalPool = (attacking.teamData.forwardScore / 2 )+ (defending.teamData.goalieScore + (defending.teamData.defenderScore / 2) + (defending.teamData.midfieldScore / 3) + (defending.teamData.forwardScore / 4));
            float attackingRange = (attacking.teamData.forwardScore / 2 ) / totalPool;
            float defendingRange = (defending.teamData.goalieScore + (defending.teamData.defenderScore / 2) + (defending.teamData.midfieldScore / 3) + (defending.teamData.forwardScore / 4)) / totalPool;

            // Check to see if attack is successful ( goal is scored )
            int randomRange = Game.random.Next(0, 100);

            if (randomRange < (attackingRange * 100))
            {
                if (attacking.name == homeTeam.name)
                    homeGoals++;
                else
                    awayGoals++;
            }
            else
            {
                // Goal is stopped
            }

        }

        public void AppointPoints()
        {
            homeTeam.standingsData.gamesPlayed += 1;
            awayTeam.standingsData.gamesPlayed += 1;

            homeTeam.standingsData.goalsFor += homeGoals;
            homeTeam.standingsData.goalsAgainst += awayGoals;

            awayTeam.standingsData.goalsFor += awayGoals;
            awayTeam.standingsData.goalsAgainst += homeGoals;

            if (homeTeamWin && !awayTeamWin) // Home Team wins
            {
                homeTeam.standingsData.gamesWon += 1;
                awayTeam.standingsData.gamesLost += 1;
            }
            else if (awayTeamWin && !homeTeamWin) // Away Team wins
            {
                awayTeam.standingsData.gamesWon += 1;
                homeTeam.standingsData.gamesLost += 1;
            }
            else if (homeTeamWin && awayTeamWin) // Match is Draw
            {
                homeTeam.standingsData.gamesDrawn += 1;
                awayTeam.standingsData.gamesDrawn += 1;
            }

            homeTeam.standingsData.UpdateData();
            awayTeam.standingsData.UpdateData();
        }
    }
}
